package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.FileReference;
import flash.net.URLRequest;

import flash.utils.ByteArray;

import mx.graphics.codec.PNGEncoder;

[SWF(width=800, height=600)]
public class SpriteSheetMaker extends Sprite
{
      protected static const LEFT_ALIGN:int = 0;
      protected static const CENTER_ALIGN:int = 1;
      protected static const RIGHT_ALIGN:int = 2;

      protected static const backgroundColour:uint = 0xFFFFFFFF;
      protected static const spacing:int = 1;
      protected static const minAnimCellWidth:int = 16;
      protected var loader:Loader;
      protected var urlRequest:URLRequest;
      protected var ranges:Vector.<Point> = new Vector.<Point>();
      protected var align:int = LEFT_ALIGN;

      public function SpriteSheetMaker()
      {
            loader = new Loader();
            urlRequest = new URLRequest("image.png");
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoadComplete);
            loader.load(urlRequest);
      }

      private function onImageLoadComplete(event:Event):void
      {
            var image:BitmapData = event.target.content.bitmapData;

            // find vertical breaks of background color between animation frames
            var range:Point = new Point(-1, -1);
            var lastVerticalLineWasBackground:Boolean = true;
            for (var x:int = 0; x < image.width; ++x)
            {
                  var foundBackground:Boolean = true;
                  for (var y:int = 0; y < image.height; ++y)
                  {
                        var pixel:uint = image.getPixel32(x, y);

                        if (pixel != backgroundColour)
                        {
                              foundBackground = false;
                              break;
                        }
                  }

                  if (lastVerticalLineWasBackground && !foundBackground)
                  {
                        range.x = x;
                  }
                  else if (!lastVerticalLineWasBackground && foundBackground)
                  {
                        range.y = x;
                        addCell(range);

                        range.x = range.y = -1;
                  }

                  lastVerticalLineWasBackground = foundBackground;
            }

            if (range.x != -1 && range.y == -1)
            {
                  range.y = image.width-1;
                  addCell(range);
            }

            if (ranges.length != 0)
            {
                  // find the maximum frame width
                  var maxWidth:int = -1;

                  for each (var range:Point in ranges)
                  {
                        var width:int = range.y - range.x;
                        if (maxWidth == -1 || maxWidth < width)
                              maxWidth = width;
                  }

                  // add some spacing between the frames
                  maxWidth += spacing * 2;

                  // set the background colour to transparent white
                  for (var x:int = 0; x < image.width; ++x)
                  {
                        for (var y:int = 0; y < image.height; ++y)
                        {
                              var pixel:uint = image.getPixel32(x, y);

                              if (pixel == backgroundColour)
                              {
                                    image.setPixel32(x, y, 0x00FFFFFF);
                              }
                        }
                  }

                  // create the bitmap that will hold our sprite sheet
                  var fixedBitmap:BitmapData = new BitmapData(maxWidth * ranges.length, image.height, true, 0);

                  // loop through each cell in the original image, and copy them to the new spritesheet
                  for (var i:int = 0; i < ranges.length; ++i)
                  {
                        var diff:int = ranges[i].y - ranges[i].x;
                        var widthDiff:Number = maxWidth - diff;
                        var shift:int = 0;

                        if (align == LEFT_ALIGN)
                              shift = 0;
                        else if (align == CENTER_ALIGN)
                              shift = Math.round(widthDiff / 2);
                        else
                              shift = widthDiff;

                        fixedBitmap.copyPixels(image, new Rectangle(ranges[i].x, 0, diff, image.height), new Point(i * maxWidth + shift, 0));
                  }

                  var display:Bitmap = new Bitmap(fixedBitmap);
                  display.x = stage.stageWidth / 2 - display.width / 2;
                  display.y = stage.stageHeight / 2 - display.height / 2;

                  this.addChild(display);

                  var pngenc:PNGEncoder = new PNGEncoder();
                  var imgByteArray:ByteArray = pngenc.encode(fixedBitmap);
                  var fr:FileReference = new FileReference( );
                  fr.save( imgByteArray, 'output.png' )
            }
      }

      protected function addCell(range:Point)
      {
            if (range.y - range.x >= minAnimCellWidth || ranges.length == 0)
            {
                  ranges.push(range.clone());
            }
            else
            {
                  var lastRange:Point = ranges[ranges.length - 1];
                  lastRange.y = range.y;
            }
      }

}
}
